#ifndef _PAGE_H
#define _PAGE_H

#include <type.h>
#include <common.h>
#include <compiler.h>

#define V_ADDR(pd, pt, offset) ((pd) << 22 | (pt) << 12 | (offset))
#define P_ADDR(ppn, offset) ((ppn << 12) | (offset))

#define P2V(paddr) ((uptr)(paddr) + KERNEL_MM_BASE)
#define V2P(vaddr) ((uptr)(vaddr) - KERNEL_MM_BASE)

typedef struct {
    union {
        struct {
            u32 present : 1;   // Page present in memory
            u32 rw : 1;        // Read-only if clear, readwrite if set
            u32 user : 1;      // Supervisor level only if clear
            u32 pwt : 1;       // write-back if clear, write-through if set
            u32 pcd : 1;       // can be cached if clear
            u32 accessed : 1;  // Has the page been accessed since last refresh?
            u32 dirty : 1;     // Has the page been written to since last refresh?
            u32 pat : 1;       // page attributes
            u32 g : 1;         // global
            u32 unused : 3;    // Amalgamation of unused and reserved bits
            u32 frame : 20;    // Frame address (shifted right 12 bits)
        };
        u32 data;

        /** 
         * Swap entry
         */
        struct {
            u32 present : 1;    // Page present, must be 0
            u32 swap_id : 8;
            u32 sign  : 3;      // signature, all set
            u32 slot : 20;
        } swap;
    };

} packed pg_entry_t;

typedef struct {
    pg_entry_t entry[1024];
} packed pg_table_t;

void page_init(void);

#endif 
